#include <cstdlib>
#include <iostream>
#include <string>
#include <ctime>

#include <opencv2/opencv.hpp>

#include "Args.h"
#include "HoursMinutesSeconds.h"
#include "utils/Logger.h"

using namespace std;

int main(int argc, char** argv) {
    Args args = Args(argc, argv);
    args.parse();

    if (args.help) {
        cout << Args::usage() << endl;
        exit(0);
    }

    else if (args.image) {
        Log << "Entering image mode." << endl;

        if (!args.noOriginal) {
            const char* inputWindow = "Image";
            cvNamedWindow(inputWindow);

            cvShowImage(inputWindow, args.image);
        }

        if (args.effects->any()) {
            const char* outputWindow = args.output.c_str();
            cvNamedWindow(outputWindow);

            IplImage *out = args.effects->apply(args.image);
            
            cvShowImage(outputWindow, out);

            cvReleaseImage(&out);
        }

        while (27 != cvWaitKey());

        cvDestroyAllWindows();
    }

    else if (args.video) {
        Log << "Entering video mode." << endl;

        IplImage *frame = cvQueryFrame(args.video);

        int fps = cvGetCaptureProperty(args.video, CV_CAP_PROP_FPS);
        int miliBetweenFrames = fps ? 1000 / fps : 60;
        int frames = cvGetCaptureProperty(args.video, CV_CAP_PROP_FRAME_COUNT);
        int seconds = fps ? frames / fps : 0;

        Log << "Video Info:" << endl;
        Log << "FPS: " << fps << endl;
        Log << "Frames: " << frames << endl;
        Log << "Seconds: " << seconds << endl;
        Log << "Time: " << HoursMinutesSeconds(seconds) << endl;

        const char* inputWindow = "Video";
        if (!args.noOriginal) 
            cvNamedWindow(inputWindow);

        const char* outputWindow = args.output.c_str();
        if (args.effects->any())
            cvNamedWindow(outputWindow);

        cvWaitKey();

        time_t begin, end;
        time(&begin);
        int framesCount = 0;

        while (frame) {
            framesCount++;
            if (!args.noOriginal) {
                cvShowImage(inputWindow, frame);
            }

            if (args.effects->any()) {
                IplImage *out = args.effects->apply(frame);

                cvShowImage(outputWindow, out);

                cvReleaseImage(&out);
            }

            switch (cvWaitKey(miliBetweenFrames)) {
                case 27:
                    goto quit;

                case 32:
                    while (32 != cvWaitKey());
            }

            frame = cvQueryFrame(args.video);
        }
        quit:

        time(&end);

        cvDestroyAllWindows();

        Log << "Real Frames Count: " << framesCount << endl;
        Log << "Running Time: " << HoursMinutesSeconds((int) difftime(end, begin)) << endl;
    }

    else {
        cerr << Args::usage() << endl;
        exit(1);
    }

    return 0;
}
